6. Touch Gestures
A gesture is a way of combining
finger movements over the screen to fire an action, instead of using a
simple touch or click. A complete touch (or mouse) move-capturing
feature is required in order for gestures to be registered, and to be
perfectly honest, today only mobile Safari and the Android browser offer
good support.
If the users need to use a gesture in your web application, it is
important to train them in what to do by showing a help message, a
sample animation, or some other kind of hint, as shown in Figure .
6.1. Swipe gesture
The swipe (also known as flip)
gesture is a touch-based browser technique typically used for going
forward and backward. For example, it is used in many photo galleries
to change the currently displayed image, and in presentations to move
from slide to slide. The gesture is simply a finger moving across the
x-axis from left to right or right to left (a horizontal swipe) or
along the y-axis from top to bottom or bottom to top (a vertical
swipe). It is a one-finger gesture, so it is compatible with almost
any touch device.
There is no standard event that captures the swipe action, so we
need to emulate it using standard events.
Warning:
On Symbian 5th edition touch
devices, strange behavior results for the mouse down, move, and up
events when a finger is used instead of the cursor. The onmousemove event is fired only once in a
finger drag operation, and the onmouseup event doesn’t fire if the finger
is moved from the original mouse-down coordinates. So, different
approaches are needed for swipe detection.
The steps will be:
Capture onmousedown (or
ontouchstart for iPhone and
compatible browsers) and start a gesture recording.
Capture onmousemove (or
ontouchmove for iPhone and
compatible browsers) and continue the gesture recording if the
move is on the x-axis (or y-axis), within a certain threshold.
Cancel the gesture if the move is on the other axis.
Capture onmouseup (or
ontouchend for iPhone and
compatible browsers) and, if the gesture was active and the
difference between the original and final coordinates is greater
than a predefined constant, define a swipe to one
direction.
The last item can be replaced with an on-the-fly verification of
the gesture inside the onmousemove
event.
Note:
If you use jQuery, there is a free plug-in available at http://plugins.jquery.com/project/swipe to detect
horizontal swiping on iPhone devices.
We can create an unobtrusive, object-oriented library for swipe
detection compatible with iPhone, Android, and other devices with the
following code:
/**
Creates a swipe gesture event handler
*/
function MobiSwipe(id) {
// Constants
this.HORIZONTAL = 1;
this.VERTICAL = 2;
this.AXIS_THRESHOLD = 30; // The user will not define a perfect line
this.GESTURE_DELTA = 60; // The min delta in the axis to fire the gesture
// Public members
this.direction = this.HORIZONTAL;
this.element = document.getElementById(id);
this.onswiperight = null;
this.onswipeleft = null;
this.onswipeup = null;
this.onswipedown = null;
this.inGesture = false;
// Private members
this._originalX = 0
this._originalY = 0
var _this = this;
// Makes the element clickable on iPhone
this.element.onclick = function() {void(0)};
var mousedown = function(event) {
// Finger press
event.preventDefault();
_this.inGesture = true;
_this._originalX = (event.touches) ? event.touches[0].pageX : event.pageX;
_this._originalY = (event.touches) ? event.touches[0].pageY : event.pageY;
// Only for iPhone
if (event.touches && event.touches.length!=1) {
_this.inGesture = false; // Cancel gesture on multiple touch
}
};
var mousemove = function(event) {
// Finger moving
event.preventDefault();
var delta = 0;
// Get coordinates using iPhone or standard technique
var currentX = (event.touches) ? event.touches[0].pageX : event.pageX;
var currentY = (event.touches) ? event.touches[0].pageY : event.pageY;
// Check if the user is still in line with the axis
if (_this.inGesture) {
if ((_this.direction==_this.HORIZONTAL)) {
delta = Math.abs(currentY-_this._originalY);
} else {
delta = Math.abs(currentX-_this._originalX);
}
if (delta >_this.AXIS_THRESHOLD) {
// Cancel the gesture, the user is moving in the other axis
_this.inGesture = false;
}
}
// Check if we can consider it a swipe
if (_this.inGesture) {
if (_this.direction==_this.HORIZONTAL) {
delta = Math.abs(currentX-_this._originalX);
if (currentX>_this._originalX) {
direction = 0;
} else {
direction = 1;
}
} else {
delta = Math.abs(currentY-_this._originalY);
if (currentY>_this._originalY) {
direction = 2;
} else {
direction = 3;
}
}
if (delta >= _this.GESTURE_DELTA) {
// Gesture detected!
var handler = null;
switch(direction) {
case 0: handler = _this.onswiperight; break;
case 1: handler = _this.onswipeleft; break;
case 2: handler = _this.onswipedown; break;
case 3: handler = _this.onswipeup; break;
}
if (handler!=null) {
// Call to the callback with the optional delta
handler(delta);
}
_this.inGesture = false;
}
}
};
// iPhone and Android's events
this.element.addEventListener('touchstart', mousedown, false);
this.element.addEventListener('touchmove', mousemove, false);
this.element.addEventListener('touchcancel', function() {
_this.inGesture = false;
}, false);
// We should also assign our mousedown and mousemove functions to
// standard events on compatible devices
}
This is a simple example of usage of our last library, swipe.js, with a div with horizontal swipe detection and
another div with vertical swipe
detection:<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
"http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Swipe Gesture Detection</title>
<meta name="viewport" content="width=device-width; initial-scale=1.0;
maximum-scale=1.0; user-scalable=0;">
<script type="text/javascript" src="swipe.js"></script>
<script type="text/javascript">
window.onload = function() {
var swipev = new MobiSwipe("vertical");
swipev.direction = swipev.VERTICAL;
swipev.onswipedown = function() { alert('down'); };
swipev.onswipeup = function() { alert('up'); };
var swipeh = new MobiSwipe("horizontal");
swipeh.direction = swipeh.HORIZONTAL;
swipeh.onswiperight = function() { alert('right'); };
swipeh.onswipeleft = function() { alert('left'); };
}
</script>
</head>
<body>
<div style="width: 100%; height: 150px; background-color: blue" id="vertical">
Vertical Swipe
</div>
<div style="width: 100%; height: 150px; background-color: red" id="horizontal">
Horizontal Swipe
</div>
</body>
</html>
Warning:
Many touch devices use the drag gesture to scroll inside the
page contents and don’t support the preventDefault feature .
That is why we should consider other ways to navigate instead of
swipe gestures.